﻿using System.Collections.Generic;
using System.Linq;

namespace RGBGame
{
    public enum NotificationReason
    {
        JoinGame=0,
        YourTurn=1,
        YouWin=2,
        YouLose=3,
        Draw=4,
        EndGameOpponentExit=5,
        EndGame=6,
        GotScore=7,
        Custom=8
    }

    public delegate void GameNotification(NotificationReason reason, object data);

    public class Room
    {
        //Game lobby
        internal static Dictionary<string, GameNotification> Lobby = new Dictionary<string, GameNotification>(); //clientId, delegate 
        
        //Matches
        internal static Dictionary<string, GameNotification> Matchs = new Dictionary<string, GameNotification>(); //clientId, delegate

        public static void AddPlayer(string clientId, GameNotification notifications)
        {
            string newPlayer = null;
            GameNotification cb = null;
            lock (Lobby)
            {
                //remove the other player from lobby and make them match
                if (Lobby.Any())
                {
                    newPlayer = Lobby.First().Key;
                    cb = Lobby[newPlayer];
                    Lobby.Remove(newPlayer);
                }
                else
                {
                    //there is no any player waiting. put this one into queue
                    Lobby.Add(clientId, notifications);
                }
            }

            if(newPlayer!=null)
            {
                CreateGame(clientId, notifications, newPlayer, cb);
            }
        }

        public static void CreateGame(string client1, GameNotification not1, string client2, GameNotification not2)
        {
            lock (Matchs)
            {
                //store delegates 
                Matchs.Add(client1, not1);
                Matchs.Add(client2, not2);
            }
            
            not1.Invoke(NotificationReason.JoinGame, new object[] { client2, 2 });
            not2.Invoke(NotificationReason.JoinGame, new object[] { client1, 1 });
            not2.Invoke(NotificationReason.YourTurn, null);
        }

        public static void GotScore(string clientId, string opId, int tileId, int resId, int turnIndex, GameNotification notification)
        {
            lock (Matchs)
            {
                if (!Matchs.ContainsKey(clientId) || !Matchs.ContainsKey(opId))
                {
                    notification.Invoke(NotificationReason.EndGame, null);
                }
                else
                {
                    Matchs[opId].Invoke(NotificationReason.GotScore, new object[] { resId, tileId, turnIndex });
                }
            }
        }

        public static void EndOfTurn(string clientId, string opId, int tileId, int currentTurn, int nextTurn, GameNotification notification)
        {
            lock (Matchs)
            {
                if (!Matchs.ContainsKey(clientId) || !Matchs.ContainsKey(opId))
                {
                    notification.Invoke(NotificationReason.EndGame, null);
                }
                else
                {
                    Matchs[opId].Invoke(NotificationReason.YourTurn, new object[] { tileId, currentTurn, nextTurn });
                }
            }
        }

        public static void ResetGame(string clientId, string opId, GameNotification gm)
        {
            RemovePlayer(clientId, opId);
            AddPlayer(clientId, gm);
        }

        public static void RemovePlayer(string clientId, string opId = null, bool crossSession = false)
        {
            GameNotification gm = null;
            lock(Matchs)
            {
                if(!string.IsNullOrEmpty(opId))
                {
                    Matchs.TryGetValue(opId, out gm);
                    Matchs.Remove(opId);
                }
                
                Matchs.Remove(clientId);
            }

            lock(Lobby)
            {
                Lobby.Remove(clientId);
            }

            if (gm != null)
            {
                gm.Invoke(NotificationReason.EndGameOpponentExit, crossSession);
            }
        }
    }
}